package com.github.data_manage.controller

import cn.idev.excel.EasyExcel
import cn.idev.excel.support.ExcelTypeEnum
import com.github.data_manage.common.CommonPage
import com.github.data_manage.common.CommonResult
import com.github.data_manage.common.ResultCode
import com.github.data_manage.dao.InvestmentsDao
import com.github.data_manage.dao.PersonInvestmentExperienceDao
import com.github.data_manage.domain.po.*
import com.github.data_manage.domain.vo.PersonModifyVo
import com.github.data_manage.domain.vo.PersonRelationVo
import com.github.data_manage.domain.vo.PersonsPageParam
import com.github.data_manage.service.PersonService
import com.github.data_manage.util.PageUtil
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.persistence.criteria.Predicate
import jakarta.servlet.http.HttpServletResponse
import jakarta.transaction.Transactional
import org.springframework.data.domain.Sort
import org.springframework.data.jpa.domain.Specification
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.util.StringUtils
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.math.BigDecimal
import java.math.RoundingMode
import java.net.URLEncoder
import java.nio.charset.StandardCharsets

/**
 *@author CHN
 *@since 2024-08-08 20:43
 */
@RestController
@Tag(name = "PersonsController", description = "成员管理")
@RequestMapping("/persons")
class PersonsController(
    private val personService: PersonService,
    private val personInvestmentExperienceDao: PersonInvestmentExperienceDao,
    private val investmentsDao: InvestmentsDao
) {

    @Operation(description = "新增/编辑成员")
    @PostMapping("/saveOrUpdate")
    @Transactional(rollbackOn = [Exception::class])
    fun saveOrUpdatePerson(@Validated @RequestBody personModifyVo: PersonModifyVo): CommonResult<String> {
        personService.saveOrUpdatePerson(personModifyVo)
        return CommonResult.success(ResultCode.SUCCESS.message)
    }

    @Operation(description = "成员信息详情")
    @GetMapping(value = ["/details"])
    fun getPersonDetailsById(@RequestParam personId: Int): CommonResult<PersonModifyVo?> {
        val personModifyVo: PersonModifyVo? = personService.getPersonDetailsById(personId)
        return if (personModifyVo != null) {
            CommonResult.success(personModifyVo)
        } else {
            CommonResult.failed(ResultCode.NO_DATA.message)
        }
    }

    @Operation(description = "成员列表")
    @RequestMapping(value = ["/list"], method = [RequestMethod.POST])
    @ResponseBody
    fun getCompanyList(@Validated @RequestBody personsPageParam: PersonsPageParam): CommonResult<CommonPage<Persons>> {
        val condition = Specification<Persons> { root, _, builder ->
            val conditions = mutableListOf<Predicate>()
            if (StringUtils.hasText(personsPageParam.companyName)) {
                conditions.add(
                    builder.like(
                        root.get<String>("currentCompany"),
                        "%${personsPageParam.companyName}%"
                    )
                )

            }
            if (StringUtils.hasText(personsPageParam.name)) {
                conditions.add(
                    builder.like(
                        root.get<String>("name"),
                        "%${personsPageParam.name}%"
                    )
                )

            }
            if (StringUtils.hasText(personsPageParam.englishName)) {
                conditions.add(
                    builder.like(
                        root.get<String>("englishName"),
                        "%${personsPageParam.englishName}%"
                    )
                )

            }
            return@Specification builder.and(*conditions.toTypedArray())
        }
        val page = PageUtil.buildJpaPage<Company>(personsPageParam.pageNum, personsPageParam.pageSize)
            .withSort(Sort.by("createTime").descending())

        return CommonResult.success(CommonPage.restPage(personService.findAll(condition, page)))
    }

    @Operation(description = "删除公司")
    @DeleteMapping(value = ["/delete"])
    @Transactional(rollbackOn = [Exception::class])
    fun deletePersonsByIds(@RequestBody personIds: Collection<Int>): CommonResult<String> {
        personService.deletePersonsByIds(personIds)
        return CommonResult.success(ResultCode.SUCCESS.message);
    }

    @GetMapping("/importTemplate")
    @Operation(description = "导入模板下载")
    fun getImportTemplate(response: HttpServletResponse) {
        response.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
        response.characterEncoding = StandardCharsets.UTF_8.name()
        response.setHeader(
            HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(
                "成员信息导入.xlsx", StandardCharsets.UTF_8
            )
        )
        response.outputStream.use { fos ->
            EasyExcel.write(fos, Persons::class.java)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet("模板")
                .doWrite {
                    emptyList<Persons>()
                }
        }
    }


    @PostMapping("/importTemplate")
    @Operation(description = "模板导入")
    @Transactional(rollbackOn = [Exception::class])
    fun importTemplate(@RequestParam("excelFile") excelFile: MultipartFile): CommonResult<String> {
        excelFile.inputStream.use { fis ->
            EasyExcel.read(fis)
                .head(Persons::class.java)
                .doReadAllSync<Persons>()
                .forEach { person ->
                    personService.save(person)
                }
        }
        return CommonResult.success(ResultCode.SUCCESS.message);
    }


    @GetMapping("/relation")
    @Operation(description = "成员关系图")
    fun personRelation(@RequestParam personId: Int): CommonResult<PersonRelationVo> {
        return CommonResult.success(personService.personRelation(personId))
    }

    @GetMapping("/investments")
    @Operation(description = "查询人员对应的所有的投资案例")
    fun getFundInvestments(@RequestParam personId: Int): CommonResult<Collection<PersonInvestmentExperience>> {
        return CommonResult.success(personInvestmentExperienceDao.findAllByPersonIdEquals(personId))
    }

    @PostMapping("/investments")
    @Operation(description = "修改人员的投资案例,有id的修改,没有的新增")
    @Transactional(rollbackOn = [Exception::class])
    open fun saveOrUpdateFundInvestments(
        @RequestParam personId: Int,
        @RequestBody personInvestmentExperience: PersonInvestmentExperience
    ): CommonResult<String> {
        if (personInvestmentExperience.id != null) {
            personInvestmentExperienceDao.findById(personInvestmentExperience.id!!)
                .ifPresent {
                    it.modified = true
                    personInvestmentExperienceDao.save(it)
                }
        }
        personInvestmentExperience.id = null
        personInvestmentExperience.personId = personId
        personInvestmentExperience.changeScale = BigDecimal.ZERO
        personInvestmentExperience.modified = false
        var investments = investmentsDao.findByName(personInvestmentExperience.investmentName!!)
        if (investments == null) {
            investments = Investments()
            investments.name = personInvestmentExperience.investmentName!!
            investments.aum = BigDecimal.ZERO
            investmentsDao.save(investments)
        }
        personInvestmentExperience.investmentId = investments.id
        personInvestmentExperience.amount =
            (personInvestmentExperience.scale?.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)
                ?.multiply(investments.aum ?: BigDecimal.ZERO)) ?: BigDecimal.ZERO ?: BigDecimal.ZERO
        personInvestmentExperience.cleanDays =
            if ((investments.mobility ?: BigDecimal.ZERO)?.compareTo(BigDecimal.ZERO) == 0) {
                BigDecimal.ZERO
            } else {
                personInvestmentExperience.amount!!.divide(
                    investments.mobility!!.multiply(BigDecimal.TEN),
                    0, RoundingMode.UP
                )
            }
        personInvestmentExperienceDao.save(personInvestmentExperience)
        return CommonResult.success(ResultCode.SUCCESS.message)
    }

    @DeleteMapping("/investments")
    @Operation(description = "删除基金的投资案例")
    @Transactional(rollbackOn = [Exception::class])
    open fun deleteFundInvestments(
        @RequestParam personInvestmentId: Int,
    ): CommonResult<String> {
        personInvestmentExperienceDao.deleteById(personInvestmentId)
        return CommonResult.success(ResultCode.SUCCESS.message)
    }

}
